/**************************************************************************************
*
*	Copyright (C) 2009 - 2012 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	IComponent.h
*
*	Description -	Instanced components can set their ID name only once. Caling SetNameID
*					will be ignored if it has an ID name set already.
*
*	Comments	-
*
*	Modification History:
*			Name			   Date					Description
*			MrCodeSushi	-	04/05/2012	-	Creation of this file
**************************************************************************************/
#ifndef _PSX_ACTOR_COMPONENT_H_
#define _PSX_ACTOR_COMPONENT_H_

#include "PulseSTD.h"
#include "ComponentTypes.h"
//#include "Actor.h"
#include "SmartPointer.h"
#include "HashTable.h"
#include "Array.h"
#include "String.h"
#include "StringID.h"
#include "XMLParser.h"
#include "ParameterSystem.h"
#include "EventSystem.h"

namespace Pulse
{


	class IComponent
	{
	public:

		IComponent( Actor *pOwner );

		virtual ~IComponent( void );

		virtual EErrorCode::Type Initialize( XMLElementPtr pElem );
		
		// Called after all objects in the scene are created (and initialized)
		virtual EErrorCode::Type Awake( void ) { return EErrorCode::OKAY; }

		// Called after all objects in the scene have awakened and is ! This allows us
		// to delay any initialization until it is really needed.
		virtual EErrorCode::Type Start( void ) { return EErrorCode::OKAY; }

		virtual const EComponent::Type GetType( void ) const = 0;

		virtual const CHAR * GetName( void ) const = 0;

		void SetOwner( Actor *pOwner );

		// NOTE: I suggest only components owned by this actor can call this
		//	and use it only temporarily. Don't store this pointer!
		Actor * GetOwnerUnsafe( void ) { return m_pOwner; }
		const Actor * GetOwnerUnsafe( void ) const { return m_pOwner; }

		virtual void Update( FLOAT dt ) { }

		void SetEnabled( BOOL bEnable ) { m_bEnabled = bEnable; }

		BOOL IsEnabled( void ) { return m_bEnabled; }

		// NOTE: This is used to check if a component type can have
		//	multiple instances in the same container.
		// In general, you would want to only have one
		//	type of your component in a scene object.
		virtual BOOL IsUnique( void ) { return TRUE; }

		IComponent * GetComponent( EComponent::Type type );

		template < typename ComponentType >
		ComponentType * GetComponent( void );

	private:

		// Just to be safe, enforce the rule of three for now.
		IComponent( void );
		IComponent( const IComponent & );
		IComponent & operator = ( const IComponent &rhs );
	
	protected:

		BOOL		m_bEnabled;
		Actor		*m_pOwner;
	};

	template < typename ComponentType >
	PSX_INLINE ComponentType * IComponent::GetComponent( void )
	{
		EComponent::Type componentType = ComponentType::GetType_Static();

		IComponent *pComponent = GetComponent( componentType );
	
		if ( pComponent == PSX_NULL )
		{
			return PSX_NULL;
		}

		if ( pComponent->GetType() != componentType )
		{
			return PSX_NULL;
		}

		return (ComponentType*)pComponent;
	}

}

#endif /* _PSX_ACTOR_COMPONENT_H_ */